package com.zzk.jpmvvmbase.base

import android.app.Application
import android.content.Context
import android.content.res.Configuration
import android.util.Log
import android.view.Gravity
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStore
import androidx.lifecycle.ViewModelStoreOwner
import com.blankj.utilcode.util.*
import com.blankj.utilcode.util.LogUtils.IFormatter
import java.util.*

/**
 *对于写BaseApp，其实我是拒绝的，但是需要提供一个很有用的功能--在Activity/fragment中获取Application级别的ViewModel
 * 所以才硬着头皮加的，如果你不想继承BaseApp，又想获取Application级别的ViewModel功能
 * 那么你可以复制该类的代码到你的自定义Application中去，然后可以自己写获取ViewModel的拓展函数即 :
 * GetViewModelExt类的getAppViewModel方法
 *
 * @ProjectName:    JetPackMVVMBase
 * @Package:        com.zzk.jpmvvmbase.base
 * @ClassName:      BaseApplication
 * @Description:
 * @Author:         brilliantzhao
 * @CreateDate:     2021.1.19 14:15
 * @UpdateUser:
 * @UpdateDate:     2021.1.19 14:15
 * @UpdateRemark:
 * @Version:        1.0.0
 */
open class BaseApplication : Application(), ViewModelStoreOwner {

    //##########################  custom variables start ##########################################

    private var TAG = javaClass.simpleName

    //
    private var sInstance: BaseApplication? = null
    var context: Context? = null

    private lateinit var mAppViewModelStore: ViewModelStore
    private var mFactory: ViewModelProvider.Factory? = null

    // 是否是主线程，解决多线程重复初始化问题
    private var isMainProcess: Boolean? = null

    //##########################  custom variables end  ###########################################

    //##########################  override custom metohds start ###################################

    override fun getViewModelStore(): ViewModelStore {
        return mAppViewModelStore
    }

    /**
     * 程序创建的时候执行
     * 这个函数是当应用开始之时就被调用了，比其他对象创建的早，这个实现要尽可能的快一点，因为创建时间直接在进程中
     * 影响到我们第一个activity/service或者receiver。如果你要重写这个方法必须调用super.onCreate()。
     */
    override fun onCreate() {
        super.onCreate()
        Log.i(TAG, "onCreate")
        isMainProcess = isMainProcess()
        // 实例个人Application类
        sInstance = this
        // 获取去全局context
        context = applicationContext
        //
        mAppViewModelStore = ViewModelStore()
        //=== init AndroidUtilCode
        // init it in the function of onCreate in ur Application
        Utils.init(this)
        //
        initUtilCodeXCrash()
    }

    /**
     * 程序终止的时候执行
     * 当终止应用程序对象时调用，不保证一定被调用，当程序是被内核终止以便为其他应用程序释放资源，那
     * 么将不会提醒，并且不调用应用程序的对象的onTerminate方法而直接终止进程
     */
    override fun onTerminate() {
        super.onTerminate()
        Log.i(TAG, "onTerminate")
    }

    /**
     * 当后台程序已经终止资源还匮乏时会调用这个方法。好的应用程序一般会在这个方法里面释放一些不必
     * 要的资源来应付当后台程序已经终止，前台应用程序内存还不够时的情况。
     */
    override fun onLowMemory() {
        super.onLowMemory()
        Log.i(TAG, "onLowMemory")
    }

    /**
     * 程序在内存清理的时候执行
     * HOME键退出应用程序、长按MENU键，打开Recent TASK都会执行
     *
     * @param level
     */
    override fun onTrimMemory(level: Int) {
        super.onTrimMemory(level)
        Log.i(TAG, "onTrimMemory")
    }

    /**
     * 配置改变时触发这个方法
     *
     * @param newConfig
     */
    override fun onConfigurationChanged(newConfig: Configuration?) {
        super.onConfigurationChanged(newConfig)
        Log.i(TAG, "onConfigurationChanged")
    }

    //##########################  override custom metohds end  ####################################

    //##########################  override third methods start ####################################

    //##########################  override third methods end  #####################################

    //##########################  custom metohds start     ########################################

    /**
     * 获取一个全局的ViewModel
     */
    fun getAppViewModelProvider(): ViewModelProvider {
        return ViewModelProvider(this, this.getAppFactory())
    }

    /**
     *
     */
    private fun getAppFactory(): ViewModelProvider.Factory {
        if (mFactory == null) {
            mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(this)
        }
        return mFactory as ViewModelProvider.Factory
    }

    /**
     * init it in ur application
     *
     * @param isShowLog
     */
    fun initUtilCodeXLog(isShowLog: Boolean) {
        val config = LogUtils.getConfig()
            .setLogSwitch(isShowLog) // 设置 log 总开关，包括输出到控制台和文件，默认开
            .setConsoleSwitch(isShowLog) // 设置是否输出到控制台开关，默认开
            .setGlobalTag(null) // 设置 log 全局标签，默认为空
            // 当全局标签不为空时，我们输出的 log 全部为该 tag，
            // 为空时，如果传入的 tag 为空那就显示类名，否则显示 tag
            .setLogHeadSwitch(true) // 设置 log 头信息开关，默认为开
            .setLog2FileSwitch(false) // 打印 log 时是否存到文件的开关，默认关
            .setDir("") // 当自定义路径为空时，写入应用的/cache/log/目录中
            .setFilePrefix("") // 当文件前缀为空时，默认为"util"，即写入文件为"util-yyyy-MM-dd$fileExtension"
            .setFileExtension(".log") // 设置日志文件后缀
            .setBorderSwitch(true) // 输出日志是否带边框开关，默认开
            .setSingleTagSwitch(true) // 一条日志仅输出一条，默认开，为美化 AS 3.1 的 Logcat
            .setConsoleFilter(LogUtils.V) // log 的控制台过滤器，和 logcat 过滤器同理，默认 Verbose
            .setFileFilter(LogUtils.V) // log 文件过滤器，和 logcat 过滤器同理，默认 Verbose
            .setStackDeep(1) // log 栈深度，默认为 1
            .setStackOffset(0) // 设置栈偏移，比如二次封装的话就需要设置，默认为 0
            .setSaveDays(3) // 设置日志可保留天数，默认为 -1 表示无限时长
            // 新增 ArrayList 格式化器，默认已支持 Array, Throwable, Bundle, Intent 的格式化输出
            .addFormatter(object : IFormatter<ArrayList<*>>() {
                override fun format(arrayList: ArrayList<*>): String {
                    return "LogUtils Formatter ArrayList { $arrayList }"
                }
            })
            .addFileExtraHead("ExtraKey", "ExtraValue")
        LogUtils.i(config.toString())
        // 改变toast显示位置
        ToastUtils.getDefaultMaker().setGravity(Gravity.CENTER, 0, 0)
    }

    /**
     * utilcodex的crash初始化
     */
    private fun initUtilCodeXCrash() {
        CrashUtils.init { crashInfo ->
            crashInfo.addExtraHead("extraKey", "extraValue")
            LogUtils.e(crashInfo.toString())
//            AppUtils.relaunchApp()
        }
    }

    /**
     * @return
     */
    private fun isMainProcess(): Boolean {
        return ProcessUtils.isMainProcess()
    }

    //##########################  custom metohds end   ############################################

}